
#include <stdint.h>
#include "n32g45x.h"
#include "board.h"

#define USARTz                  USART2
#define USARTz_IRQn             USART2_IRQn
#define USARTz_DR_Base          (USART2_BASE + 0x04)

#define USARTz_Tx_DMA_CH        DMA1_CH7
#define USARTz_Tx_DMA_IRQn      DMA1_Channel7_IRQn
#define USARTz_Tx_DMAx          DMA1
#define USARTz_Tx_DMA_FLAG      DMA1_FLAG_TC7
#define USARTz_Tx_DMA_REMAP     DMA1_REMAP_USART2_TX

int driv_trans_uart_init(uint32_t baudrate)
{
    NVIC_InitType NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel                   = USARTz_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    NVIC_InitStructure.NVIC_IRQChannel                   = USARTz_Tx_DMA_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    DMA_InitType DMA_InitStructure;
    DMA_StructInit(&DMA_InitStructure);
    DMA_DeInit(USARTz_Tx_DMA_CH);
    DMA_RequestRemap(USARTz_Tx_DMA_REMAP, USARTz_Tx_DMAx, USARTz_Tx_DMA_CH, ENABLE);

    DMA_InitStructure.PeriphAddr     = USARTz_DR_Base;
    DMA_InitStructure.MemAddr        = 0;
    DMA_InitStructure.Direction      = DMA_DIR_PERIPH_DST;
    DMA_InitStructure.BufSize        = 0;
    DMA_InitStructure.PeriphInc      = DMA_PERIPH_INC_DISABLE;
    DMA_InitStructure.DMA_MemoryInc  = DMA_MEM_INC_ENABLE;
    DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_BYTE;
    DMA_InitStructure.MemDataSize    = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.CircularMode   = DMA_MODE_NORMAL;
    DMA_InitStructure.Priority       = DMA_PRIORITY_VERY_HIGH;
    DMA_InitStructure.Mem2Mem        = DMA_M2M_DISABLE;
    DMA_Init(USARTz_Tx_DMA_CH, &DMA_InitStructure);

    USART_InitType USART_InitStructure;
    USART_StructInit(&USART_InitStructure);
    USART_InitStructure.BaudRate            = baudrate;
    USART_InitStructure.WordLength          = USART_WL_8B;
    USART_InitStructure.StopBits            = USART_STPB_1;
    USART_InitStructure.Parity              = USART_PE_NO;
    USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
    USART_InitStructure.Mode                = USART_MODE_RX | USART_MODE_TX;
    USART_Init(USARTz, &USART_InitStructure);
    USART_ConfigInt(USARTz, USART_INT_RXDNE, ENABLE);
    DMA_ConfigInt(USARTz_Tx_DMA_CH, DMA_INT_TXC, ENABLE);
    USART_EnableDMA(USARTz, USART_DMAREQ_TX, ENABLE);
    USART_Enable(USARTz, ENABLE);

    return 0;
}

int driv_trans_uart_write(const uint8_t* data, uint32_t len)
{
    USARTz_Tx_DMA_CH->TXNUM = (uint32_t)len;
    USARTz_Tx_DMA_CH->MADDR = (uint32_t)data;
    DMA_EnableChannel(USARTz_Tx_DMA_CH, ENABLE);
    return 0;
}

void DMA1_Channel7_IRQHandler(void)
{
    if (DMA_GetIntStatus(USARTz_Tx_DMA_FLAG, USARTz_Tx_DMAx) != RESET)
    {
        DMA_ClrIntPendingBit(USARTz_Tx_DMA_FLAG, USARTz_Tx_DMAx);
        driv_trans_uart_tx_cb();
    }
}

void USART2_IRQHandler(void)
{
    if (USART_GetIntStatus(USARTz, USART_INT_RXDNE) != RESET)
    {
        uint8_t data = USART_ReceiveData(USARTz);
        driv_trans_uart_rx_cb(data);
    }

    /* Determine if an error flag still exists and clear the error flag */
    if ((USART_GetFlagStatus(USARTz, USART_FLAG_OREF) != RESET)  || \
        (USART_GetFlagStatus(USARTz, USART_FLAG_NEF) != RESET)  || \
        (USART_GetFlagStatus(USARTz, USART_FLAG_PEF) != RESET)  || \
        (USART_GetFlagStatus(USARTz, USART_FLAG_FEF) != RESET))
    {
        /*Read the sts register first,and the read the DAT register to clear the all error flag*/
        (void)USARTz->STS;
        (void)USARTz->DAT;
        /* Under normal circumstances, all error flags will be cleared when the upper data is read and will not be executed here;
           users can add their own processing according to the actual scenario. */
    }
}
